package org.hawk.gwt.ppc;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Represents configuration parser from command line options.
 * Separates GWT arguments from preprocessor ones.
 * 
 * @author alex.bereznevatiy@gmail.com
 */
class CmdArgs extends AbstractConfiguration implements Configuration {
	private static final String ARG_PREFIX = "-P";
	private static final String GWT_ARG_PREFIX = "-";
	private static final Set<String> GWT_EMPTY_ARGS;
	
	static{
		Set<String> rez = new HashSet<String>();
		rez.add("-ea");
		rez.add("-XdisableClassMetadata");
		rez.add("-XdisableCastChecking");
		rez.add("-validateOnly");
		rez.add("-draftCompile");
		rez.add("-compileReport");
		GWT_EMPTY_ARGS = Collections.unmodifiableSet(rez);
	}
	
	private String[] compilerArguments;

	CmdArgs(String[] args) {
		super(parseArguments(args), parseModules(args));
		compilerArguments = extractCompilerArguments(args);
	}

	private static String[] extractCompilerArguments(String[] args) {
		List<String> result = new LinkedList<String>();
		for(String arg : args){
			if(!arg.startsWith(ARG_PREFIX)){
				result.add(arg);
			}
		}
		return result.toArray(new String[result.size()]);
	}
	
	private static Map<String,Object> parseArguments(String[] args){
		Map<String,Object> result = new HashMap<String, Object>();
		for (int i=0; i<args.length; i++) {
			if (args[i] == null) {
				throw new IllegalArgumentException("NULL");
			} else if(args[i].startsWith(ARG_PREFIX)){
				parseArgument(args[i],result);
			} else {
				String name = args[i];
				Object value = null;
				if (GWT_EMPTY_ARGS.contains(name)) {
					value = Boolean.TRUE;
				} else {
					i++;
					value = i < args.length ? args[i] : "";
				}
				
				result.put(name, value);
			}
		}
		return Collections.unmodifiableMap(result);
	}
	
	private static void parseArgument(String arg, Map<String,Object> result) {
		arg = arg.substring(ARG_PREFIX.length());
		if (arg.indexOf('=') < 0) {
			result.put(arg, Boolean.TRUE);
			return;
		}
		String[] tmp = arg.split("=", 2);
		try {
			result.put(tmp[0],Integer.valueOf(tmp[1]));
		} catch(NumberFormatException ex) {
			result.put(tmp[0],tmp[1]);
		}
	}
	
	private static List<String> parseModules(String[] args) {
		args = extractCompilerArguments(args);
		
		List<String> modules = new LinkedList<String>();
		for(int i = 0; i < args.length; i++) {
			if (!args[i].startsWith(GWT_ARG_PREFIX)) {
				modules.add(args[i]);
			}
			else if(!GWT_EMPTY_ARGS.contains(args[i])) {
				i++;
			}
		}
		return Collections.unmodifiableList(modules);
	}

	/**
	 * @return arguments to GWT compiler. All processor-specific
	 * arguments will be omitted.
	 */
	public String[] getCompillerArguments() {
		return compilerArguments;
	}
}
